<template>
  <div class="container">
    <div class="tootip">
      <div>按Shift开始自由绘制箭头线段</div>
      <el-button class="margin-lt-15" size="small" type="primary" @click="stopDraw">停止绘制</el-button>
    </div>
    <div id="map-container"></div>
  </div>
</template>
<script setup lang='ts'>
import { onMounted } from 'vue';
import 'ol/ol.css'
import { Map, View, Feature } from 'ol'
import VectorSource from 'ol/source/Vector'
import { Vector as VectorLayer } from 'ol/layer'
import { Style, Stroke as StyleStroke, Icon as StyleIcon } from 'ol/style'
import { Point as GeomPoint, LineString as GeomLineString } from 'ol/geom'
import Draw from 'ol/interaction/Draw'
import { useTianTileLayer, projection } from '@/hooks'
import { TiandiTileLayerConfigEnum } from '@/enum'
import { CENTER_BLHX_LONG_LAT } from '@/constant'
import { getImageUrl } from '@/utils'
import { KeyEventEnum } from '@/enum'

let map: Map, source: VectorSource, vector: VectorLayer<VectorSource>, draw: Draw;

// 自由绘制用到; 通过坐标回显添加点、箭头用不到
const styleFunc = function(feature: any) {
  const geometry = feature.getGeometry()!;
  const styles = [
    new Style({
      stroke: new StyleStroke({
        color: '#ffcc33',
        width: 2,
      }),
    }),
  ];
  (geometry as any).forEachSegment(function (start: number[], end: number[]) {
    const dx = end[0] - start[0];
    const dy = end[1] - start[1];
    const rotation = Math.atan2(dy, dx);
    // arrows
    styles.push(new Style({
      geometry: new GeomPoint(end),
      image: new StyleIcon({
        src: getImageUrl('arrow.png'),
        scale: 0.2,
        anchor: [0.75, 0.5],
        rotateWithView: true,
        rotation: -rotation,
      }),
    }))
  })
  return styles;
}

onMounted(() => {
  initMap()
  window.addEventListener(KeyEventEnum.ON_KEY_DOWN, keyDown)
})

// 初始化地图
function initMap() {
  source = new VectorSource();
  vector = new VectorLayer({
    source: source,
    style: styleFunc,
  });
  map = new Map({
    target: 'map-container',
    layers: [ ...useTianTileLayer(TiandiTileLayerConfigEnum.SL), vector ],
    view: new View({
      center: CENTER_BLHX_LONG_LAT,
      zoom: 3,
      maxZoom: 17,
      minZoom: 1,
      projection: projection,
    })
  })
  getCoordinate()
}

// 获取坐标
function getCoordinate() {
  // 根据坐标 添加点、线
  const coordinates = [
    [170.168644,60.003816],
    [196.219216,59.930029],
    [216.373455,34.240125]
  ]
  addLine(coordinates)
}

/**
 * 添加线 传入多个坐标即可
 * @param coordinates 
 */
function addLine(coordinates: Array<number[]>) {
  if(!map) return
  const Line = new Feature({
    type: 'line',
    geometry: new GeomLineString(coordinates),
  });
  // Line.setStyle(new Style({
  //   fill: new StyleFill({
  //     color: 'rgba(255, 255, 255, 0.2)'
  //   }),
  //   stroke: new StyleStroke({
  //     color: 'blue',
  //     width: 1
  //   })
  // }))
  Line.setStyle(arrowLineStyles) // 添加箭头
  const vectorSource = new VectorSource({
    features: [Line]
  })
  const vectorLayer = new VectorLayer({
    source: vectorSource
  })
  map.addLayer(vectorLayer)
  return { Line, vectorSource, vectorLayer }
}

// 箭头样式
function arrowLineStyles(feature: any, resolution: any) {
  let styles = [];
  // 线条样式
  let backgroundLineStyle = new Style({
    stroke: new StyleStroke({
      color: "blue",
      width: 1,
    }),
  });
  styles.push(backgroundLineStyle);
  let geometry = feature.getGeometry();
  // 获取线段长度
  const length = geometry.getLength();
  // 箭头间隔距离（像素）
  const step = 50;
  // 将间隔像素距离转换成地图的真实距离
  const StepLength = step * resolution;
  // 得到一共需要绘制多少个 箭头
  const arrowNum = Math.floor(length / StepLength);
  const rotations: any[] = [];
  const distances = [0];
  geometry.forEachSegment(function (start: number[], end: number[]) {
    let dx = end[0] - start[0];
    let dy = end[1] - start[1];
    let rotation = Math.atan2(dy, dx);
    distances.unshift(Math.sqrt(dx ** 2 + dy ** 2) + distances[0]);
    rotations.push(rotation);
  });
  // 利用之前计算得到的线段矢量信息，生成对应的点样式塞入默认样式中
  // 从而绘制内部箭头
  for (let i = 1; i < arrowNum; ++i) {
    const arrowCoord = geometry.getCoordinateAt(i / arrowNum);
    const d = i * StepLength;
    const grid = distances.findIndex((x) => x <= d);
    styles.push(new Style({
      geometry: new GeomPoint(arrowCoord),
      image: new StyleIcon({
        src: getImageUrl('arrow.png'),
        opacity: 0.8,
        anchor: [0.5, 0.5],
        rotateWithView: false,
        // 读取 rotations 中计算存放的方向信息
        rotation: -rotations[distances.length - grid - 1],
        scale: 0.2,
      }),
    }))
  }
  return styles;
}

// 按下Shift键 自由绘制箭头线段
function keyDown(event: KeyboardEvent) {
  if((event && event.key === 'Shift') || !event) {
    if(draw) map.removeInteraction(draw)
    draw = new Draw({
      source: source,
      type: 'LineString',
    })
    map.addInteraction(draw);
  }
}

function stopDraw() {
  if(!draw) return
  map.removeInteraction(draw)
}
</script>
<style scoped>
.container {
  width: 100%;
  height: 100%;
}
.tootip {
  width: 100%;
  height: 35px;
  display: flex;
  align-items: center;
  padding-left: 15px;
  color: black;
  font-size: 14px;
}
#map-container {
  width: 100%;
  height: calc(100% - 35px);
}
.margin-lt-15 {
  margin-left: 15px;
}
</style>